//
//  FoundationEx.swift
//  Risac
//
//  Created by remy on 2018/3/27.
//

import Foundation

public protocol MetaType {}
extension MetaType {
    public var metaTypeName: String {
        return type(of: self).metaTypeName
    }
    public static var metaTypeName: String {
        return String(describing: self)
    }
}
extension NSObject: MetaType {}

public struct WeakBox<T: AnyObject>: Hashable {
    public private(set) weak var value: T?
    public init (_ value: T) {
        self.value = value
    }
    public func hash(into hasher: inout Hasher) {
        if let value = value {
            hasher.combine(ObjectIdentifier(value).hashValue)
        }
    }
    public static func == (lhs: WeakBox<T>, rhs: WeakBox<T>) -> Bool {
        return lhs.hashValue == rhs.hashValue
    }
}

public final class QueueTask {
    let queue: DispatchQueue
    var task: (() -> Void)?
    
    private init(_ queue: DispatchQueue,
                 _ delay: TimeInterval,
                 _ task: @escaping () -> Void) {
        self.queue = queue
        self.task = task
        if delay > 0.0 {
            queue.asyncAfter(deadline: DispatchTime.now() + delay) {
                self.task?()
                self.task = nil
            }
        } else {
            queue.async {
                self.task?()
                self.task = nil
            }
        }
    }
    
    deinit {
        Risac.print("\(String(describing: self)) has deinit")
    }
    
    @discardableResult
    public static func queue(_ queue: DispatchQueue,
                             delay: TimeInterval = 0.0,
                             task: @escaping () -> Void) -> Self {
        return self.init(queue, delay, task)
    }
    
    @discardableResult
    public static func main(delay: TimeInterval = 0.0, task: @escaping () -> Void) -> Self {
        return self.init(DispatchQueue.main, delay, task)
    }
    
    @discardableResult
    public static func global(qos: DispatchQoS.QoSClass = .default,
                              delay: TimeInterval = 0.0,
                              task: @escaping () -> Void) -> Self {
        return self.init(DispatchQueue.global(qos: qos), delay, task)
    }
    
    public func cancel(_ executeTask: Bool = false) {
        guard let task = task else { return }
        if executeTask { task() }
        self.task = nil
    }
}
